import { GameConfig } from "../configs/GameConfig";
import { Attribute } from "../etc/Attribute";
import { Constants } from "../etc/Constants";
import Appearance from "../model/Appearance";
import RobotModel from "../model/RobotModel";
import { MotionModuleC } from "../motion/MotionModule";
import { EnumBagItemGrid, ItemModuleData, ItemModuleS } from "./ItemModule";

export class PlayerModuleData extends Subdata {
    @Decorator.persistence()
    reserveAttribute: Attribute.AttributeArray;
    
    get dataName(): string { return 'PlayerModuleData' }
    
    protected initDefaultData() {
        this.reserveAttribute = {};
        this.save(true);
    }
}

export class PlayerModuleC extends ModuleC<PlayerModuleS,PlayerModuleData>{
    // 即时属性存根(用于记录属性变更)
    private playerStashedAttrBuffer = {};
    // 即时属性容器
    private attribute: Attribute.AttributeValueObject = new Attribute.AttributeValueObject();

    // 跳跃次数(落地清零)
    private jumpTime = 0;

    static defaultCameraOffset:Vector
    static defaultCameraArmLength:number
    static defaultPlayerRunSpeed:number

    protected onStart(): void {
        PlayerModuleC.defaultCameraOffset = Camera.currentCamera.localTransform.position
        PlayerModuleC.defaultCameraArmLength = Camera.currentCamera.springArm.length
        PlayerModuleC.defaultPlayerRunSpeed = Player.localPlayer.character.maxWalkSpeed

        this.data.onDataChange.add(this.onPlayerAttributeDataChanged, this);
        this.syncPlayerStashedAttribute();
    }

    protected onUpdate(dt: number): void {
        if(this.jumpTime > 0 && !this.localPlayer.character.isJumping){
            this.jumpTime = 0
        }
    }

    getAttr(type: Attribute.EnumAttributeType): number {
        if (!Attribute.IsStashAttribute(type)) return this.attribute.getValue(type)
        return this.data.reserveAttribute[type] || 0;
    }
    
    movement(dir: Vector) {
        
    }

    jump() {
        if(this.jumpTime > 1) return
        // 第二次跳
        if(this.jumpTime == 1){
            let animation = this.localPlayer.character.loadAnimation('150691')
            animation.play()
        }
        let z = this.localPlayer.character.velocity.z;
        let jumpForceAddition = this.getAttr(Attribute.EnumAttributeType.jumpForceAddition)
        
        this.localPlayer.character.addImpulse(new Vector(0, 0, -z + 800 + jumpForceAddition), true)
        this.jumpTime++

        SoundService.playSound(Constants.SoundGuid.Jump,1,3);
    }

    attack(){
        // 朝向最近的玩家
        let nearCharacter:Character
        let minDis = 9e8
        let myPos = this.localPlayer.character.worldTransform.position
        for (const player of Player.getAllPlayers()) {
            if(player == this.localPlayer) continue
            let distance = Vector.distance(myPos, player.character.worldTransform.position)
            if(distance < minDis){
                minDis = distance
                nearCharacter = player.character
            }
        }
        for (const robot of RobotModel.robotMap.values()) {
            let distance = Vector.distance(myPos, robot.character.worldTransform.position)
            if(distance < minDis){
                minDis = distance
                nearCharacter = robot.character
            }
        }
        if(nearCharacter && minDis <= 500){
            let dir = Vector.subtract(nearCharacter.worldTransform.position, this.localPlayer.character.worldTransform.position)
            dir.z = 0
            dir.normalize()
            dir.add(this.localPlayer.character.worldTransform.position)
            this.localPlayer.character.worldTransform.lookAt(dir)
        }
        ModuleService.getModule(MotionModuleC).invokeMotion('normal_atk')
    }

    // 比对变更属性
    private onPlayerAttributeDataChanged() {
        this.syncPlayerStashedAttribute();
    }
    
    // 同步玩家数据到缓存数据
    private syncPlayerStashedAttribute() {
        Object.assign(this.playerStashedAttrBuffer, this.data.reserveAttribute);
    }
    
    // 服务器发送的初始化属性列表
    net_init_attr(attributeArray: Attribute.AttributeArray) {
        for (let type in attributeArray) {

            let value = attributeArray[type];
            this.attribute.setAttribute(Number(type), value);

            if(Number(type) == Attribute.EnumAttributeType.runSpeedAddition){
                Player.localPlayer.character.maxWalkSpeed = PlayerModuleC.defaultPlayerRunSpeed + value
            }
        }
    }
    
    // 服务器发送的属性变更
    net_change_attr(type: Attribute.EnumAttributeType, value: number) {
        this.attribute.setAttribute(type, value);
    }

    // 当服务器索要玩家姓名时发送玩家233名称
    net_register_player_name_when_server_appearance_ready(){
        let nickName = AccountService.getNickName()
        if(SystemUtil.isPIE){
            nickName = `本地玩家${this.localPlayerId}`
        }
        this.server.net_register_player_name(nickName)
    }

}

export class PlayerModuleS extends ModuleS<PlayerModuleC,PlayerModuleData>{
    private appearanceMapping:Map<number, Appearance> = new Map()
    private playerAttributeMap: Map<number, Attribute.AttributeValueObject> = new Map();

    protected onStart(): void {
        ModuleService.getModule(ItemModuleS).onPlayerAppearanceChanged.add(this.refreshPlayerWeapon,this)
        
    }

    protected onUpdate(dt: number): void { }
    
    protected onPlayerEnterGame(player: mw.Player) {
        let playerID = player.playerId

        player.character.collisionWithOtherCharacterEnabled = false;

        player.character.asyncReady().then((character)=>{
            character.displayName = " ";  
        })

        // 初始化玩家信息脚本
        this.initPlayerAppearanceScript(player)
        
        if(!this.playerAttributeMap.has(playerID)){
            let attrVo = new Attribute.AttributeValueObject()
            this.playerAttributeMap.set(playerID, attrVo)
            this.getClient(playerID).net_init_attr(attrVo.attributeArray);
        }
    }
    
    protected onPlayerLeft(player: mw.Player): void {
        // 外观
        let appearance = this.appearanceMapping.get(player.playerId)
        if(appearance) appearance.destroy()

        if(this.appearanceMapping.has(player.playerId)) this.appearanceMapping.delete(player.playerId)
        // 属性
        if(this.playerAttributeMap.has(player.playerId)) this.playerAttributeMap.delete(player.playerId);
    }

    getPlayerAppearance(playerID:number):Appearance | undefined{
        return this.appearanceMapping.get(playerID)
    }

    // 注册玩家名称并广播至房间内玩家
    @Decorator.noReply()
    net_register_player_name(nickName:string){
        let playerAppearanceScript = this.appearanceMapping.get(this.currentPlayerId)
        if(!playerAppearanceScript) return

        playerAppearanceScript.playerName = nickName
    }


    reducePlayerAttr(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        if (!Player.getPlayer(playerID)) return //已下线
        if (Attribute.IsStashAttribute(type)) {
            this.reducePlayerAttrStash(playerID, type, value);
            return
        }
        this.reducePlayerAttrIT(playerID, type, value);
    }

    addPlayerAttr(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        if (!Player.getPlayer(playerID)) return //已下线
        if (Attribute.IsStashAttribute(type)) {
            this.addPlayerAttrStash(playerID, type, value);
            return
        }
        this.addPlayerAttrIT(playerID, type, value);
    }
    
    getPlayerAttr(playerID: number, type: Attribute.EnumAttributeType): number {
        if (!Player.getPlayer(playerID)) return 0 //已下线
        // 是否为存储属性
        if (Attribute.IsStashAttribute(type)) {
            return this.getPlayerData(playerID).reserveAttribute[type] || 0;
        }
        return this.playerAttributeMap.get(playerID).getValue(type);
    }

    // 减少玩家储存属性(不随游戏结束清空的属性)
    private reducePlayerAttrStash(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        let data = this.getPlayerData(playerID);
        data.reserveAttribute[type] = data.reserveAttribute[type] - value;
        data.save(true);
    }

    // 增加玩家储存属性(不随游戏结束清空的属性)
    private addPlayerAttrStash(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        let data = this.getPlayerData(playerID);
        data.reserveAttribute[type] += value;
        data.save(true);
    }

    // 减少玩家即时属性
    private reducePlayerAttrIT(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        let vo = this.playerAttributeMap.get(playerID);
        vo.reduceValue(type, value);
        this.syncChangePlayerAttr(playerID, type);
    }

    // 增加玩家即时属性
    private addPlayerAttrIT(playerID: number, type: Attribute.EnumAttributeType, value: number) {
        let vo = this.playerAttributeMap.get(playerID);
        vo.addValue(type, value);
        this.syncChangePlayerAttr(playerID, type);
    }
    
    // 同步属性变更(单一)
    private syncChangePlayerAttr(playerID: number, type: Attribute.EnumAttributeType) {
        let attrVo = this.playerAttributeMap.get(playerID);
        this.getClient(playerID).net_change_attr(type, attrVo.getValue(type));
    }

    // 初始化玩家外观脚本
    private async initPlayerAppearanceScript(player:Player){
        let playerID = player.playerId
        if(this.appearanceMapping.has(playerID)) return

        let appearance = await Script.spawnScript(Appearance)
        appearance.init(playerID)

        this.appearanceMapping.set(playerID, appearance)
        // 索要玩家姓名
        this.getClient(playerID).net_register_player_name_when_server_appearance_ready()
        // 刷新玩家武器外观
        this.refreshPlayerWeapon(playerID)
    }

    // 更新玩家武器外观
    private refreshPlayerWeapon(playerID:number){
        let appearance = this.appearanceMapping.get(playerID)
        if(!appearance) return
    }
}